//
//$Id: test_mpi.cpp 667 2011-02-26 18:59:32Z Oleg.Bulychov $

#include "stdafx.h"

#include "src/heo/include/alloc_page.h"
#include "src/heo/include/alloc_lite.h"
#include "src/heo/include/alloc_big.h"
#include "src/heo/include/sys_api.h"
#include "src/heo/include/lf_endl.h"
//#include "src/heo/include/random.h"
#include "src/heo/include/dynamic_bit_array.h"
#include "src/heo/include/transmit_dynamic_bit_array.h"
#include "src/heo/include/easy_mpi.h"
#include "src/heo/include/unit_tester.h"
#include "src/heo/include/console_color.h"
#include "src/heo/include/stream_visitor.h"

using namespace std;


template<>
struct test<111>
{
    inline bool run()
    {
        mpi::communicator comm;
        int rank  = comm.rank();
        int np = comm.size();
        int t = rank + 100;
        int* gt = new int[np];
        if (rank != 0)
        {
            comm.gather(&t, 1, 0);
        }
        else
        {
            //DEBUG_BREAK__;
            comm.gather(&t, 1, gt, 0);
            meta::ostream_visitor kout(cout);
            kout.visit_Array(gt, np, "gather", 0);
        }
        delete[] gt;
        
        return true;
    }
};

template<>
struct test<222>
{
    inline bool run()
    {
        mpi::communicator comm;
        int rank  = comm.rank();
        int np = comm.size();
        int t = rank + 100;
        int* gt = new int[np];
        comm.all_gather(&t, 1, gt);
        meta::ostream_visitor kout(cout);
        kout.visit_Array(gt, np, "gather", 0);
        delete[] gt;
        
        return true;
    }
};

template<>
struct test<3>
{
    inline bool run()
    {
        cout << "start test" << endl;
        for (int i = 0; i < 15; ++i)
            run_Ex();
        cout << "end test" << endl;
        return true;
    }

    bool run_Ex()
    {
        mpi::communicator comm;
        int rank  = comm.rank();
        int np = comm.size();
        int prev = (np + rank - 1) % np;
        int next = (rank + 1)      % np;

        int error = 0;
        dynamic_bit_array<>* pd = new dynamic_bit_array<>();
        pd->resize(148488);

        dynamic_bit_array<> a;
        a.resize(148488);
        a.set(1);

        if ((rank & 1) == 0)
        {
            mpi::ibsend ois(next, comm);
            ois << a;
            
            //ois.wait();

            //for (;;)
            //{
            //    int f = 0;
            //    ois.test(f);
            //    if (f)
            //        break;
            //    sys_api::Yield_Thread();
            //}

            delete pd;
            pd = NULL;
            big_allocator::squeeze();
            pd = new dynamic_bit_array<>();
            pd->resize(148488);
            pd->set();
            comm.test_Isend();
        }
        if ((rank & 1) != 0)
        {
            dynamic_bit_array<> b;
            sys_api::Sleep(100);
            mpi::recv(prev, comm) >> b;
            size_t j = 0;
            if (a.size() == b.size())
            {
                for (; j < a.size(); ++j)
                {
                    if (a[j] != b[j])
                        break;
                }
            }
            bool flag = a.equals(b);
            VERIFY_(flag == (j >= a.size()));
            {
                if (j < a.size())
                {
                    std::cout << color<ltred, black> << "a != b at " << j << no_color << std::endl;
                    if (b.size() > 0)
                        std::cout << "b[0]=" << *b.front_block() << std::endl;
                    ++error;
                }
                else
                {
                    std::cout << "a == b" << std::endl;
                }
            }
        }
        comm.test_Isend();
        comm.barrier();
        if (pd)
            delete pd;
        
        return !error;
    }
};

void Mem_Panic(size_t cbRequired, size_t* pcbAvailable)
{
    //TODO fix me...
    std::cout << "mem panic: " << cbRequired << " bytes required" << lf;
    if (pcbAvailable)
        std::cout << "but " << *pcbAvailable << " available" << lf;
}

int main(int argc, char* argv[])
{
    cout << "Hello" << endl;
    setlocale(LC_ALL, "C");//:decimal point must be '.'

    mpi::implementation impl(argc, argv);
    mpi::communicator comm;
    int rank  = comm.rank();
    int np = comm.size();
    cout << "rank " << rank << " from " << np << lf;

    VERIFY_(lite_allocator::construct(1, 1));//:memory in MB per thread
    VERIFY_(big_allocator::construct(1, 4));//:memory in MB per thread
    //random_generator::randomize(1, 1100101, rank);

    comm.barrier();
    bool r = tester<16>().run_Test();
    comm.barrier();
    if (r)
        cout << "All right" << endl;

    big_allocator::destruct();
    lite_allocator::destruct();
    page_allocator::destruct();
    return 0;
}

